﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace System.Windows.Forms
{
    
    /// <summary>
    /// DataGridView功能控件扩展。主要增加了多标题行，标题列合并及多行标题文本。
    /// </summary>
    public class DataGridViewExt : DataGridView
    {
        //public static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #region 字段定义

        /// <summary>多维列标题的树结构
        /// 
        /// </summary>
        private TreeView _headerTree;

        /// <summary>标题文本中的空格符是否替换为回车符
        /// 
        /// </summary>
        private bool _spaceToReturn = true;

        /// <summary>树的最大层数
        /// 
        /// </summary>
        private int headLevels;

        /// <summary>一维列标题的高度
        /// 
        /// </summary>
        private int headHeight;

        /// <summary>所有叶节点
        /// 
        /// </summary>
        private IList<TreeNode> leafLists = new List<TreeNode>();

        #endregion

        #region 属性定义

        /// <summary>多维列标题的树结构
        /// 
        /// </summary>
        [CategoryAttribute("扩展"),//Extend
          DescriptionAttribute("多维列标题的树结构")
        ]
        public TreeView HeaderTree
        {
            get { return _headerTree; }
            set { _headerTree = value; }
        }

        /// <summary>
        /// 标题文本中的空格符是否替换为回车符.
        /// </summary>
        /// <value><c>true</c> if [space to return]; otherwise, <c>false</c>.</value>
        [CategoryAttribute("扩展"), 
        DescriptionAttribute("标题文本中的空格符是否替换为回车符"), 
        DefaultValueAttribute(true)]
        public bool SpaceToReturn
        {
            get { return _spaceToReturn; }
            set { _spaceToReturn = value; }
        }

        #endregion

        #region 方法函数

        /// <summary>初始化
        /// 求最大层数、列头总高，并保存所有叶节点，处理标题换行
        /// </summary>
        public void init()
        {
            TreeView tnc = new TreeView();
            this.headLevels = 1;//初始为1
            this.leafLists.Clear();
            foreach (DataGridViewColumn column in this.Columns)
            {
                string[] headTexts = column.HeaderText.Split(',');
                if (this.headLevels < headTexts.Length) this.headLevels = headTexts.Length;
                TreeNode pnode = null;
                for (int i = 0; i < headTexts.Length; i++)
                {
                    if (this.SpaceToReturn) headTexts[i] = headTexts[i].Replace(' ', '\n');
                    if (headTexts[i] == "")
                    {
                        if (i == 0) pnode = (tnc.Nodes.Count > 0) ? tnc.Nodes[tnc.Nodes.Count - 1] : null;
                        else pnode = pnode.Nodes[pnode.Nodes.Count - 1];
                    }
                    else
                    {
                        TreeNode node = new TreeNode(headTexts[i]);
                        if (i == 0) tnc.Nodes.Add(node);
                        else pnode.Nodes.Add(node);
                        pnode = node;
                    }
                }
                this.leafLists.Add(pnode);
            }

            this.HeaderTree = tnc;

            this.headHeight = this.ColumnHeadersHeight;
            this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
            this.ColumnHeadersHeight = this.headHeight * this.headLevels;//列头总高=一维列高*层数

        }

        /// <summary>获得合并标题字段的宽度
        /// 
        /// </summary>
        /// <param name="node">字段节点</param>
        /// <returns>字段宽度</returns>
        private int GetUnitHeaderWidth(TreeNode node)
        {
            int uhWidth = 0;
            //获得最底层字段的宽度
            if (node.Nodes == null)
                return this.Columns[GetColumnListNodeIndex(node)].Width;

            if (node.Nodes.Count == 0)
                return this.Columns[GetColumnListNodeIndex(node)].Width;

            //获得非最底层字段的宽度
            for (int i = 0; i <= node.Nodes.Count - 1; i++)
            {
                uhWidth = uhWidth + GetUnitHeaderWidth(node.Nodes[i]);
            }
            return uhWidth;
        }

        /// <summary>获得底层字段索引
        /// 
        /// </summary>
        ///' <param name="node">底层字段节点</param>
        /// <returns>索引</returns>
        /// <remarks></remarks>
        private int GetColumnListNodeIndex(TreeNode node)
        {
            for (int i = 0; i <= leafLists.Count - 1; i++)
            {
                if (leafLists[i].Equals(node))
                    return i;
            }
            return -1;
        }

        ///<summary>绘制合并表头
        ///
        ///</summary>
        ///<param name="node">合并表头节点</param>
        ///<param name="e">绘图参数集</param>
        ///<param name="level">结点深度</param>
        ///<remarks></remarks>
        public void PaintUnitHeader(TreeNode node, CellPaintingArgs e)
        {
            //根节点时退出递归调用
            if (e.Level == 0)
                return;

            RectangleF uhRectangle;
            int uhWidth;
            SolidBrush gridBrush = new SolidBrush(this.GridColor);
            SolidBrush backColorBrush = new SolidBrush(e.BackColor);
            Pen gridLinePen = new Pen(gridBrush);

            uhWidth = GetUnitHeaderWidth(node);

            //与原贴算法有所区别在这。
            if (node.Nodes.Count == 0)
            {
                uhRectangle = new Rectangle(e.Left,
                            e.Top + node.Level * headHeight,
                            uhWidth - 1,
                            headHeight * (headLevels - node.Level) - 1);
            }
            else
            {
                uhRectangle = new Rectangle(
                            e.Left - e.Width,
                            e.Top + node.Level * headHeight,
                            uhWidth - 1,
                            headHeight - 1);
            }

            //画矩形
            e.Graphics.FillRectangle(backColorBrush, uhRectangle);

            //写标题字符串
            StringFormat format = new System.Drawing.StringFormat();
            if (this.ColumnHeadersDefaultCellStyle.WrapMode == DataGridViewTriState.False) format.FormatFlags = StringFormatFlags.NoWrap;
            if (this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleCenter ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleLeft ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleRight)
                format.Alignment = StringAlignment.Center;
            else if (this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.BottomCenter ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.BottomLeft ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.BottomRight)
                format.Alignment = StringAlignment.Far;
            if (this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.BottomCenter ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleCenter ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.TopCenter)
                format.LineAlignment = StringAlignment.Center;
            else if (this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleRight ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.TopRight ||
                this.ColumnHeadersDefaultCellStyle.Alignment == DataGridViewContentAlignment.BottomRight)
                format.LineAlignment = StringAlignment.Far;
            e.Graphics.DrawString(node.Text, this.ColumnHeadersDefaultCellStyle.Font
                                    , Brushes.Black, uhRectangle, new System.Drawing.StringFormat(format));

            //划底线
            e.Graphics.DrawLine(gridLinePen
                                , uhRectangle.Left
                                , uhRectangle.Bottom
                                , uhRectangle.Right
                                , uhRectangle.Bottom);
            //划左端线
            //e.Graphics.DrawLine(gridLinePen
            //                    , uhRectangle.Left - 1
            //                    , uhRectangle.Top
            //                    , uhRectangle.Left - 1
            //                    , uhRectangle.Bottom);
            //划右端线
            e.Graphics.DrawLine(gridLinePen
                                , uhRectangle.Right
                                , uhRectangle.Top
                                , uhRectangle.Right
                                , uhRectangle.Bottom);
            //float left = uhRectangle.Left + uhRectangle.Width / 2 - e.Graphics.MeasureString(node.Text, this.ColumnHeadersDefaultCellStyle.Font).Width / 2 - 1;
            //log.Debug(node.Text + ":(" + uhRectangle.Left + "," + uhRectangle.Top + ")-(" + uhRectangle.Right + "," + uhRectangle.Bottom + ") "+left+"\n");
            //递归调用()
            if (node.Parent != null)
            {
                if (e.IsFirstNode)
                {
                    e.Level -= 1;
                    e.IsFirstNode = node.Parent.PrevNode == null;
                    PaintUnitHeader(node.Parent, e);
                }
                else if (e.IsLastNode)
                {
                    e.IsLastNode = node.Parent.NextNode == null;
                    int uhWidth1 = 0;
                    TreeNode preNode = node.PrevNode;
                    while (preNode != null)
                    {
                        uhWidth1 = uhWidth1 + GetUnitHeaderWidth(preNode);
                        preNode = preNode.PrevNode;
                    }
                    e.Level -= 1;
                    e.Left = int.Parse(uhRectangle.Left.ToString());
                    e.Width = uhWidth1;
                    PaintUnitHeader(node.Parent, e);
                }
            }
        }

        #endregion

        //重画表头
        protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
        {
            try
            {
                //行标题不重写
                if (e.ColumnIndex < 0)
                {
                    base.OnCellPainting(e);
                    return;
                }

                //if (headLevels == 1)
                //{
                //    base.OnCellPainting(e);
                //    return;
                //}

                //绘制表头
                if (e.RowIndex == -1)
                {
                    if (_headerTree != null)
                    {
                        if (headLevels == 0)
                        {
                            init();
                        }
                        TreeNode node = this.leafLists[e.ColumnIndex];
                        CellPaintingArgs arg = new CellPaintingArgs(e);
                        arg.Level = headLevels;
                        arg.IsFirstNode = node.PrevNode == null;
                        arg.IsLastNode = node.NextNode == null;
                        PaintUnitHeader(node, arg);

                        e.Handled = true;
                    }
                    else
                    {
                        base.OnCellPainting(e);
                    }
                }
            }
            catch (Exception ex)
            {
                e.Handled = false;
                MessageBox.Show(this, ex.Message, "Error");
            }
        }
    }

    /// <summary>
    /// 用于传递参数
    /// </summary>
    public class CellPaintingArgs
    {
        public Color BackColor { get; set; }
        public int Left { get; set; }
        public int Top { get; set; }
        public Graphics Graphics { get; set; }
        public int Level { get; set; }
        /// <summary>
        /// 当前节点的前面节点宽度和.
        /// </summary>
        /// <value>The width.</value>
        public int Width { get; set; }
        /// <summary>
        /// 是否是本级第一个节点.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is first node; otherwise, <c>false</c>.
        /// </value>
        public bool IsFirstNode { get; set; }
        /// <summary>
        /// 是否是本级最后一个节点.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is last node; otherwise, <c>false</c>.
        /// </value>
        public bool IsLastNode { get; set; }

        public CellPaintingArgs(DataGridViewCellPaintingEventArgs e)
        {
            this.BackColor = e.CellStyle.BackColor;
            this.Graphics = e.Graphics;
            this.Left = e.CellBounds.Left;
            this.Top = e.CellBounds.Top;
            this.Level = 1;
            this.Width = 0;
            this.IsFirstNode = true;
            this.IsLastNode = false;
        }
    }

}
